#include <bits/stdc++.h>
using namespace std;
// int mod=109;
// int n,m;//种类,一排多少个
//排列组合
// int main()
// {
//     cin>>n>>m;
//     long long x=n;
//     for(int i=0;i<m-1;i++)
//     {
//         x=(x%mod*(n-1)%mod)%mod;
//     }
//     cout<<x<<endl;
//     return 0;
// }

//会超时
// int n,m;
// int x1,y,x2,y2;
// bool found=false;
// int dx[4]={0,0,-1,1};
// int dy[4]={-1,1,0,0};
// void dfs(vector<vector<char>>& ret,int i,int j,vector<vector<bool>>& visit,int& pathlen,int& minlen)
// {
//     if(i==x2&&j==y2)
//     {
//         minlen=min(minlen,pathlen);
//         found=true;
//         return;
//     }
//     for(int k=0;k<4;k++)
//     {
//         int x=i+dx[k],y=j+dy[k];
//         if(x>=1&&x<=n&&y>=1&&y<=m&&!visit[x][y]&&ret[x][y]=='.')
//         {
//             visit[x][y]=true;
//             pathlen++;
//             dfs(ret,x,y,visit,pathlen,minlen);
//             pathlen--;
//             visit[x][y]=false;
//         }
//     }
// }
// int main()
// {
//     cin>>n>>m;
//     cin>>x1>>y>>x2>>y2;
//     vector<vector<char>> ret(n+1,vector<char>(m+1));
//     vector<vector<bool>> visit(n+1,vector<bool>(m+1,0));
//     for(int i=1;i<=n;i++)
//         for(int j=1;j<=m;j++)cin>>ret[i][j];
    
//     if(x1==x2&&y2==y)
//     {
//         cout<<0<<endl;
//         return 0;
//     }
//     if(ret[x2][y2]=='*')
//     {
//         cout<<-1<<endl;
//         return 0;
//     }

//     int minlen=INT_MAX;
//     int pathlen=0;
//     visit[x1][y]=true;
//     dfs(ret,x1,y,visit,pathlen,minlen);
//     cout<<(found?minlen:-1)<<endl;
//     return 0;
// }

// int n,m;
// int x1,y,x2,y2;
// int dx[4]={0,0,-1,1};
// int dy[4]={-1,1,0,0};
// int bfs(vector<vector<char>>& ret,vector<vector<int>>& visit)
// {
//     //剪枝
//     if(x1==x2&&y==y2)return 0;
//     if(ret[x2][y2]=='*')return -1;
//     //存储一个键值对，存储每个坐标的信息
//     queue<pair<int,int>> q;
//     q.push({x1,y});
//     visit[x1][y]=0;//从当前点开始搜索，需要置为0
//     while(!q.empty())
//     {
//         //取出队头元素
//         auto [a,b]=q.front();
//         q.pop();
//         //从当前点开始搜素
//         for(int k=0;k<4;k++)
//         {
//             int x=a+dx[k],y1=b+dy[k];
//             //当前点需要在范围内且这个点需要没有访问过
//             if(x>=1&&x<=n&&y1>=1&&y1<=m&&visit[x][y1]==-1&&ret[x][y1]=='.')
//             {
//                 q.push({x,y1});
//                 visit[x][y1]=visit[a][b]+1;//当前点是从(a,b)来的，所以(x,y1)需要这样处理
//                 if(x==x2&&y1==y2)return visit[x][y1];//提前返回
//             }
//         }
//     }
//     return -1;
// }
// int main()
// {
//     cin>>n>>m;
//     cin>>x1>>y>>x2>>y2;
//     vector<vector<char>> ret(n+1,vector<char>(m+1));
//     //-1代表未访问过的点，除此之外的值代表到达这个点时走过的路径长度
//     vector<vector<int>> visit(n+1,vector<int>(m+1,-1));
//     for(int i=1;i<=n;i++)
//         for(int j=1;j<=m;j++)cin>>ret[i][j];
    
//     cout<<bfs(ret,visit)<<endl;
//     return 0;
// }


//下一个区间是否需要新的主持人取决于它的开始时间是否大于前一个的结束时间
//可以看出只需要存储前一个区间的结束时间即可，只有当没有一个区间的结束时间小于下一个区间的开始时间时
//才新加入这个区间的结束时间，如果此时来了一个放在那个区间都可以的呢？此时遍历就是n^2的时间复杂度了
//通过上面的分析，我们可以得到，只要下一个区间的开始事件大于前面已经存在的最小结束时间，他就不需要增加新的主持人
//我们可以定义一个小根堆来实现，它的插入时间复杂度未n*logn,满足题意
struct com
{
    bool operator()(const int a,const int b){return a > b;}
};
//如果仿函数中有自定义的函数，设置为类内成员会有问题，尽量设置为类外全局或局部变量
priority_queue<int,vector<int>,com> q;
class Solution {
    public:
        int minmumNumberOfHost(int n, vector<vector<int> >& startEnd) {
            int m=startEnd.size();
            sort(startEnd.begin(),startEnd.end());
            q.push(startEnd[0][1]);
            for(int i=1;i<m;i++)
            {
                if(startEnd[i][0]>=q.top())
                {
                    q.pop();
                    q.push(startEnd[i][1]);
                }
                else q.push(startEnd[i][1]);
            }
            return q.size();
        }
    };
int main()
{
    int n;cin>>n;
    vector<vector<int>> ret={{1,3},{2,4}};
    cout<<Solution().minmumNumberOfHost(n,ret)<<endl;
    // cout<<(q.empty()?-1:q.top())<<endl;
    return 0;
}